////
// @file bitmapTest.cc
// @brief
//
// @author ycm
// @email 2023080912019@uestc.edu.cn
//

#include "../catch.hpp"
#include <ii/roaring.hh>
#include <db/record.h>
#include <db/table.h>
#include <iostream>

using namespace roaring;

TEST_CASE("ii/roaring.hh")
{
    SECTION("main")
    {
        Roaring r;
        for (uint32_t i = 100; i < 1000; ++i) {
            r.add(i);
        }
        // check number of elements
        REQUIRE(r.cardinality() == 900);
        Roaring64Map r64;
        for (uint64_t i = 18000000000000000100ull; i < 18000000000000001000ull; i++) {
            r64.add(i);
        }
        REQUIRE(r64.cardinality() == 900);
    }
    SECTION("common")
    {
        Roaring r;
        REQUIRE(r.isEmpty());
        // add single value
        r.add(1);
        REQUIRE(r.contains(1));
        r.add(0ull);
        REQUIRE(r.contains(0ull));
        REQUIRE(!r.isEmpty());

        // add serial values
        uint32_t values[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
        r.addMany(std::size(values), values);
        for (uint32_t i = 0; i < std::size(values); ++i) {
            REQUIRE(r.contains(values[i]));
        }

        // add range
        r.addRange(100, 200);
        for (uint32_t i = 100; i < 200; ++i) {
            REQUIRE(r.contains(i));
        }
        REQUIRE(!r.contains(200));
        r.addRangeClosed(200, 299);
        for (uint32_t i = 200; i < 300; ++i) {
            REQUIRE(r.contains(i));
        }

        // remove range
        r.removeRange(100, 200);
        for (uint32_t i = 100; i < 200; ++i) {
            REQUIRE(!r.contains(i));
        }
        r.removeRangeClosed(200, 299);
        for (uint32_t i = 200; i < 300; ++i) {
            REQUIRE(!r.contains(i));
        }

        // remove serial values
        for (auto it: values) {
            REQUIRE(r.removeChecked(it));
            REQUIRE(!r.contains(it));
        }

        // remove single value
        r.remove(1);
        REQUIRE(!r.contains(1));
        r.remove(0ull);
        REQUIRE(!r.contains(0ull));
        REQUIRE(r.isEmpty());
    }
    SECTION("operation")
    {
        Roaring r1, r2;
        r1.addRange(0, 200);
        r2.addRange(100, 300);
        Roaring r3 = r1 | r2; // union
        for (uint32_t i = 0; i < 300; ++i) {
            REQUIRE(r3.contains(i));
        }
        r3.clear();

        r3 = r1 & r2; // intersection
        for (uint32_t i = 0; i < 100; ++i) {
            REQUIRE(!r3.contains(i));
        }
        for (uint32_t i = 100; i < 200; ++i) {
            REQUIRE(r3.contains(i));
        }
        for (uint32_t i = 200; i < 300; ++i) {
            REQUIRE(!r3.contains(i));
        }
        r3.clear();

        r3 = r1 ^ r2; // symmetric difference
        for (uint32_t i = 0; i < 100; ++i) {
            REQUIRE(r3.contains(i));
        }
        for (uint32_t i = 100; i < 200; ++i) {
            REQUIRE(!r3.contains(i));
        }
        for (uint32_t i = 200; i < 300; ++i) {
            REQUIRE(r3.contains(i));
        }
        r3.clear();

        r3 = r1 - r2; // difference
        for (uint32_t i = 0; i < 100; ++i) {
            REQUIRE(r3.contains(i));
        }
        for (uint32_t i = 100; i < 300; ++i) {
            REQUIRE(!r3.contains(i));
        }
    }
    SECTION("iteration")
    {
        Roaring r;
        for (uint32_t i = 6; i < 10; ++i) {
            r.add(i);
        }
        r.addRange(10, 100);
        uint32_t values[] = {0, 1, 2, 3, 4, 5};
        r.addMany(std::size(values), values);
        uint32_t i = 0;
        for (auto it: r) {
            REQUIRE(it == i++);
        }
        REQUIRE(i == 100);
    }
    SECTION("serialization")
    {
        char buffer[1024] = {0};
        Roaring r;
        r.addRange(0xDEADFFFE, 0xDEAF0001);
        r.add(1);
        r.add(0x00011001);
        Roaring rCopy = r | Roaring();
        REQUIRE(rCopy == r);
        REQUIRE(r.write(buffer) == r.getSizeInBytes());
        REQUIRE(r.getSizeInBytes() == roaring::api::roaring_bitmap_portable_size_in_bytes(&r.roaring));

        // read length
        size_t len = r.getSizeInBytes();
        REQUIRE(len == api::roaring_bitmap_portable_deserialize_size(buffer, 2048));

        r.clear();
        REQUIRE(r.isEmpty());

        // read from buffer
        r = Roaring::read(buffer);
        REQUIRE(!r.isEmpty());
        REQUIRE(r == rCopy);
    }
}
TEST_CASE("db/bitmap")
{
    SECTION("record")
    {
        // 模拟数据库记录类（因为原db::Record未提供实现）
        class MockRecord
        {
          public:
            MockRecord()
                : data_(nullptr)
                , length_(0)
            {}
            ~MockRecord() { delete[] data_; } // 析构时自动释放内存

            // 设置记录数据（深拷贝）
            void setData(const char *data, size_t length)
            {
                delete[] data_; // 释放旧数据
                data_ = new char[length];
                memcpy(data_, data, length); // 复制数据
                length_ = length;
            }

            // 获取记录数据指针
            const char *getData() const { return data_; }

            // 获取记录数据长度
            size_t getLength() const { return length_; }

          private:
            char *data_;    // 数据存储指针
            size_t length_; // 数据长度
        };

        //=== 测试1：正常位图存储和读取 ===//
        // 创建测试位图并填充数据
        Roaring bitmap;
        bitmap.add(1); // 添加单个值
        bitmap.add(2);
        bitmap.add(3);
        bitmap.addRange(10, 20); // 添加数值范围[10,20)
        bitmap.add(1000);        // 添加大数值

        // 序列化位图到缓冲区
        size_t serialized_size = bitmap.getSizeInBytes(); // 获取序列化后大小
        char *buffer = new char[serialized_size];         // 分配缓冲区
        bitmap.write(buffer);                             // 执行序列化

        // 将序列化数据存入Record
        MockRecord record;
        record.setData(buffer, serialized_size);
        delete[] buffer; // 释放临时缓冲区

        // 验证记录存储的数据长度是否正确
        REQUIRE(record.getLength() == serialized_size);

        // 从Record中反序列化位图
        Roaring loaded_bitmap = Roaring::read(record.getData());

        // 验证反序列化后的位图
        REQUIRE(
            loaded_bitmap.cardinality() ==
            bitmap.cardinality());        // 元素数量相同
        REQUIRE(loaded_bitmap == bitmap); // 位图内容完全一致

        //=== 测试2：空位图边界情况 ===//
        Roaring empty_bitmap; // 创建空位图
        buffer = new char[empty_bitmap.getSizeInBytes()];
        empty_bitmap.write(buffer); // 序列化空位图
        record.setData(buffer, empty_bitmap.getSizeInBytes());
        delete[] buffer;

        // 读取并验证空位图
        Roaring loaded_empty = Roaring::read(record.getData());
        REQUIRE(loaded_empty.isEmpty());       // 确认是空位图
        REQUIRE(loaded_empty == empty_bitmap); // 内容一致
    }
}